#include <sys/poll.h>
#include <cassert>

#include "Poller.h"
#include "Channel.h"
#include "Timestamp.h"

Poller::Poller(EventLoop *loop) : ownerLoop_(loop){}

Poller::~Poller() {}

Timestamp Poller::poll(int timeoutMs, ChannelList *activeChannels) {
    int numEvents = ::poll(& * pollfds_.begin(), pollfds_.size(), timeoutMs);
    // 调用poll函数, 因为vector是STL保证的底层以数组形式保存的存在, 所以直接获取数组元素的首地址就是我们要传入的事件数组的地址了
    // 获取当前活动IO事件, 然后填充后传入到activeChannels中去
    Timestamp now(Timestamp::now());
    if(numEvents){
        fillActiveChannels(numEvents, activeChannels);
    }else if(numEvents == 0){
        // 监听失败, 进行日志记录
    }else{
        // 错误, 也使用日志记录
    }
    return now;
    // 这里应该是返回一个完成的事件戳的
}

/**
 * 遍历pollfds_, 找出活动事件的文件描述符
 * 将对应活动事件的回调处理器填充到activeChannels中去, 这里numEvent就是我们要遍历的文件描述符数量
 * @param numEvents
 * @param activeChannels
 */
void Poller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const {
    for(PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd){
        if (pfd->revents > 0){
            --numEvents;
            ChannelMap ::const_iterator ch = channels_.find(pfd->fd);
            assert(ch != channels_.end());
            Channel * channel = ch->second;
            assert(channel->fd() == pfd->fd);
            channel->set_revents(pfd->revents);
            activeChannels->push_back(channel);
        }
    }
}

/**
 * 负责维护和更新pollfds_数组,
 */
void Poller::updateChannel(Channel *channel) {
    assertInLoopThread();
    if (channel->index() < 0){
        // 如果发现对应的文件描述符管理的没有被添加到pollfds_数组中, 就会进行添加操作
        assert(channels_.find(channel->fd()) == channels_.end());
        struct pollfd pfd;
        pfd.fd = channel->fd();
        pfd.events = static_cast<short>(channel->events());
        pfd.revents = 0;
        // 这里就是配置对应的文件描述符事件了
        pollfds_.push_back(pfd);
        // 添加到pollfds_数组中, 用于后续观察
        int idx = static_cast<int>(pollfds_.size()) - 1;
        channel->set_index(idx);
        // 获取对应的索引, 并设置到对应的channel中
        channels_[pfd.fd] = channel;
        // 将对应的文件描述符与回调处理类添加到map集合中
    }else{
        assert(channels_.find(channel->fd()) != channels_.end());
        assert(channels_[channel->fd()] == channel);
        int idx = channel->index();
        assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
        struct pollfd & pfd = pollfds_[idx];
        // 通过对应的索引获取文件描述符
        assert(pfd.fd == channel->fd() || pfd.fd == -1);
        pfd.events = static_cast<short>(channel->events());
        // 设置文件描述符的事件
        pfd.revents = 0;
        if(channel->isNoneEvent()){
            // 这里是如果对应的事件处理函数不想再关心这个文件描述符的话了, 就将对应的fd设置为 -1, 让poll忽略这个文件描述符
            pfd.fd = -1;
        }
    }
}